

//已连接的设备
import 'dart:async';

import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:xsdk_flutter/xsdk/framework/bean/x_bean_device.dart';
import 'package:xsdk_flutter/xsdk/operation/x_mixin_release.dart';
import 'package:xsdk_flutter/xsdk/utils/bluetooth/support/x_notify_bluetooth_device_callback.dart';
import 'package:xsdk_flutter/xsdk/utils/queue/x_bean_queue_message.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_log.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_number.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_string.dart';

class XBleConnectApi with XMixinRelease{

  String bluetoothAddress;
  BluetoothDevice device;
  XBaseDevice baseDevice;

  //有效的特征值通道
  //String characteristicId= characteristic.uuid.toString()
  List<BluetoothCharacteristic> listCharacteristics=[];

  //是否自动重连
  Timer? _timer;
  bool _isAutoReconnect=true;

  XBleConnectApi({
    required this.bluetoothAddress,
    required this.device,
    required this.baseDevice,
  }){

    //监听状态,初始化
    device.connectionState.listen((BluetoothConnectionState state) async {
      //XLogUtils.printLog('---设备当前状态state: $state');

      try{
        if(state==BluetoothConnectionState.connected){
          isConnecting=false;
          XLogUtils.printLog('---当前蓝牙设备初步建立连接,正在发现服务, device: ${device.platformName}, ${device.remoteId.str}');
          //发现服务
          _discoverServices(device:device,baseDevice:baseDevice);

        }else if(state==BluetoothConnectionState.disconnected){
          isConnecting=false;
          XLogUtils.printLog('---当前蓝牙设备已断开! device: ${device.platformName}, ${device.remoteId.str}');
          //更新状态
          baseDevice.isConnected=false;
          XBluetoothDeviceNotifyCallback.instance.bleDeviceConnectStatusCallback(isConnect: false, bluetoothAddress: baseDevice.bluetoothAddress!);

          //重连
          if(_isAutoReconnect){
            _timer ??= Timer(const Duration(seconds: 2),(){
              //
              XLogUtils.printLog('---蓝牙自动重连中: device: ${device.platformName}, ${device.remoteId.str}');
              //
              connect();
              //
              _timer?.cancel();
              _timer = null;
            }
            );
          }

        }

      }catch(e){
        XLogUtils.printLog('---ble connectionState listen 报错: $e');
      }

    },onError: (e){
      isConnecting=false;
    });
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is XBleConnectApi &&
              runtimeType == other.runtimeType &&
              bluetoothAddress == other.bluetoothAddress;

  @override
  int get hashCode => bluetoothAddress.hashCode;


  //释放资源
  @override
  void xRelease() {
    //
    _isAutoReconnect=false;

    try{
      _disconnectDevice();
    }catch(e){
      XLogUtils.printLog('----XBleConnectApi xRelease error:$e');
    }

  }

  ///////////////////

  //是否正在连接中,避免心跳包重复连接,等待处理抛多次异常
  bool isConnecting=false;
  //1.连接 ok
  void connect(){
    try{
      if(!isConnecting){
        //不是在连接中,建立新连接
        isConnecting=true;
        XLogUtils.printLog('---开始连接蓝牙设备: ${baseDevice.deviceName}, ${baseDevice.bluetoothAddress}');
        device.connect(timeout: const Duration(seconds: 5)).onError((error, stackTrace){
          //实测:连接失败,会在这里抛出异常
          XLogUtils.printLog('----蓝牙设备连接失败 onError: $error, $stackTrace');
          isConnecting=false;
        });
      }else{
        XLogUtils.printLog('---蓝牙设备正在连接中: ${baseDevice.deviceName}, ${baseDevice.bluetoothAddress}');
      }

    }catch(e){
      //实测:连接失败,不会在这里抛出异常,异步要使用onError拦截
      isConnecting=false;
    }

  }

  /*
  2.写入内容(国内打印机使用gbk,否则乱码) ok
  bool allowLongWrite: android/iOS的ble连接时,是否强制使用mtu最大值写入(需外围设备支持长写ble协议),解决打印大图片分包过多打印慢问题,建议最大30k左右图片
  true: mtu=512-3, false则按实际mtu值, 注意:写入时需要按mtu值分包传输
   */
  Future<bool> writeMsg (
      XBaseQueueMessage msg,
      {
        String? characteristicId,
        bool isMTULongWrite = false,
      }
      ) async {
    try{

      if(!baseDevice.isConnected){
        //断开连接
        if(!msg.isHeartbeatCommand){
          XLogUtils.printLog('---_writeMsg写入失败,设备断开连接,msgId=${msg.msgId}');
        }
        return false;
      }

      if(msg.message_Uint8List==null && XStringUtils.isEmpty(msg.message)){
        return false;
      }

      if(msg.message_Uint8List==null && !XStringUtils.isEmpty(msg.message)){
        if(baseDevice.isGBK){
          msg.message_Uint8List=XStringUtils.stringToUint8List_gbk('${msg.message}\n');
        }else{
          msg.message_Uint8List=XStringUtils.stringToUint8List_utf8('${msg.message}\n');
        }
      }

      //支持数据分包
      //characteristic.write为异步方法,在前添加await可在这里的try...catch捕获错误

      BluetoothCharacteristic? characteristic;
      if(XStringUtils.isEmpty(characteristicId)){
        //取第1个
        if(listCharacteristics.isNotEmpty){
          characteristic=listCharacteristics[0];
        }
      }else{
        //指定characteristicId
        for(BluetoothCharacteristic item in listCharacteristics){
          if(item.uuid.str==characteristicId){
            characteristic=item;
            break;
          }
        }
      }

      if(characteristic!=null){
        /*
        原始支持发送数据包大小,默认23
        android,设置mtu=512后,有些系统只能到达100,
        注意，iOS将不允许MTU大小的请求，并将始终尝试协商最大的MTU (iOS支持最大MTU大小185)
        */
        int mtu= device.mtuNow;
        //XLogUtils.printLog('---mtu=$mtu');

        //底层在connect连接时,已经请求获取最大mtu,不必再次重新获取
        // if(XFlutterUtils.isAndroid()){
        //   XLogUtils.printLog('---原始mtu= $mtu');
        //   //注意，iOS将不允许MTU大小的请求，并将始终尝试协商最大的MTU,动态改变 (iOS支持最大MTU大小185)
        //   mtu= await device.requestMtu(512);
        // }

        if(isMTULongWrite){
          mtu=512;
        }

        //实测真正发送时,提示100> max:97,因此用回原始mtu还要减少一些
        mtu=mtu-3;//底层mtu-3,这里分包也同样要-3

        if(mtu<=0){
          mtu=20;
        }

        //XLogUtils.printLog('---当前mtu= $mtu');
        if(msg.message_Uint8List!.length>mtu){
          int length=msg.message_Uint8List!.length;
          //
          int size=XNumberUtils.d2int_ceil(length/mtu);
          //
          XLogUtils.printLog("---当前mtu= $mtu, 写入数据length= $length, 分包个数size= $size");
          //
          for(int i=0;i<size;i++){
            if(i==size-1){
              //XLogUtils.printLog("---start= ${i*mtu}, end=$length");
              List<int> data=msg.message_Uint8List!.getRange(i*mtu, length).toList();
              await characteristic.write(data,allowLongWrite: isMTULongWrite);
            }else{
              //XLogUtils.printLog("---start= ${i*mtu}, end=${(i+1)*mtu}");
              List<int> data=msg.message_Uint8List!.getRange(i*mtu, (i+1)*mtu).toList();
              await characteristic.write(data,allowLongWrite: isMTULongWrite);
            }
          }
        }else{
          await characteristic.write(msg.message_Uint8List!,allowLongWrite: isMTULongWrite);
        }

        //处理成功写入消息
        return true;

      }

    }catch(e){
      //characteristic.write为异步方法,在前添加await可在这里捕获错误
      XLogUtils.printLog('---_writeMsg写入失败,trycatch报错: $e');
    }

    return false;
  }

  ///////////////////


  //监听特征接收消息 默认GBK, ok
  void _receiveMsg(BluetoothCharacteristic characteristic) async{
    try{

      //需要设置,否则无法接收蓝牙信息,同时实测重复执行会报错
      bool isSuccess=await characteristic.setNotifyValue(true);

      XLogUtils.printLog('---设置接收BluetoothCharacteristic信息,setNotifyValue=$isSuccess');

      //
      characteristic.onValueReceived.listen((List<int> data) {
        String msg='';
        if(baseDevice.isGBK){
          msg=XStringUtils.uint8ListToString_gbk(data);
        }else{
          msg=XStringUtils.uint8ListToString_utf8(data);
        }
        XLogUtils.printLog('---receive msg: device=${characteristic.remoteId.str}, characteristicId=${characteristic.uuid.toString()}, msg=$msg');
        XBluetoothDeviceNotifyCallback.instance.receiveBleDeviceMsgCallback(
          conn:this,
          bluetoothAddress: characteristic.remoteId.str,
          characteristicId: characteristic.uuid.toString(),
          msgBytes:data,
          msg: msg,
        );
      },onError: (e){
        //实测: 断链不会触发报错
        XLogUtils.printLog('---_receiveMsg,onError错误: $e');
      });
    }catch(e){
      XLogUtils.printLog('---_receiveMsg, trycatche错误: $e');
    }

  }

  //断开连接ok
  void _disconnectDevice(){
    device.disconnect().onError((error, stackTrace) => XLogUtils.printLog('_disconnectDevice报错: $error, $stackTrace'));
  }

  //发现服务(已连接设备后),并打印所有服务和特征值 ok
  void _discoverServices(
      {
        required BluetoothDevice device,
        required XBaseDevice baseDevice,
      }
      )
  {

    //init
    listCharacteristics.clear();

    device.discoverServices().then(
            (List<BluetoothService> services)
        {
          for (BluetoothService service in services) {
            XLogUtils.printLog('---serviceId: ${service.uuid.toString()}');
            List<BluetoothCharacteristic> characteristics=service.characteristics;
            //
            for(BluetoothCharacteristic characteristic in characteristics){
              //
              CharacteristicProperties properties=characteristic.properties;
              //指定characteristicId
              if(baseDevice.characteristicIds!=null && baseDevice.characteristicIds!.isNotEmpty){
                for(String characteristicId in baseDevice.characteristicIds!){
                  if(characteristic.uuid.toString()==characteristicId){
                    listCharacteristics.add(characteristic);
                    break;
                  }
                }
              }else{
                //没哟指定characteristicId,则根据properties判断能读写的characteristicId
                //自动适配蓝牙芯片协议,判断可读可写,否则写入报错
                if(properties.write&&properties.read){
                  XLogUtils.printLog('------发现可写可读 characteristicId: ${characteristic.uuid.toString()}, properties= ${properties.toString()}');
                  listCharacteristics.add(characteristic);
                }else{
                  XLogUtils.printLog('------不可读写:characteristicId: ${characteristic.uuid.toString()}, properties= ${properties.toString()}');
                }
              }
              // List<BluetoothDescriptor> descriptors=characteristic.descriptors;
              // descriptors.forEach((BluetoothDescriptor descriptor) {
              //   XLogUtils.printLog('---------descriptorsId: ${descriptor.uuid.toString()}');
              // });
            }

            // includedServices.forEach((BluetoothService includedService) {
            //   XLogUtils.printLog('------includedServiceId: ${includedService.uuid.toString()}');
            //
            //   List<BluetoothCharacteristic> includedCharacteristics=includedService.characteristics;
            //   includedCharacteristics.forEach((BluetoothCharacteristic includedCharacteristic) {
            //     XLogUtils.printLog('---------includedCharacteristicId: ${includedCharacteristic.uuid.toString()}');
            //   });
            // });

            XLogUtils.printLog('------------------------------------------');
          }
        })
        .whenComplete((){
          XLogUtils.printLog('---完成发现ble蓝牙服务');

          baseDevice.isConnected=true;
          XBluetoothDeviceNotifyCallback.instance.bleDeviceConnectStatusCallback(isConnect: true, bluetoothAddress: baseDevice.bluetoothAddress!);

          if(baseDevice.isReceiveDeviceMsg){
            for(BluetoothCharacteristic characteristic in listCharacteristics){
              //监听特征接收信息
              CharacteristicProperties properties=characteristic.properties;
              if(properties.read){
                _receiveMsg(characteristic);
              }
            }
          }

        }
    ).onError((error, stackTrace){
      XLogUtils.printLog('_discoverServices onError: $error,$stackTrace');
    });
  }


}
